#include "ParamReader.h"

std::ifstream ParamReader::cfgFile;

//Experiment
int			ParamReader::EXP_NUM_RUNS						=1;			//number of trials (for statistical significant)
int			ParamReader::EXP_NUM_EPISODES					=50;		//number of episodes in each run
int			ParamReader::EXP_NUM_STEPS						=300;		//max number of steps in each episode
int			ParamReader::EXP_TYPE							=0;			//type of experiment: (0) planning, (1) offline learning, (2) online learning


//agent
 int		ParamReader::AGNT_USE_GENERALIZATION_TIME		=1000;		//param: time when we start using generalization
 bool		ParamReader::AGNT_LEARN_GENERALIZATION			=true;		//param:
 bool		ParamReader::AGNT_USE_GENERALIZATION			=true;		//param: are we using generalization or not
 int		ParamReader::AGNT_USE_GENERALIZATION_END_TIME	=-1;		//param: time we stop using generalization
 int		ParamReader::AGNT_LEARN_GENERALIZATION_END_TIME	= -1; //param: when do we stop adding instances to FA
 int		ParamReader::AGNT_SOLVE_PERIOD					=200;		//param: interval for solving our model
 int		ParamReader::AGNT_BATCH_LEARNING_TIME			=200;		//param:
 int		ParamReader::AGNT_BATCH_LEARNING_END_TIME		= 20000;		//param:
 int		ParamReader::AGNT_RUN_TIMEOUT					=100;		//param:

 double		ParamReader::GAMMA								=0.95;		//param:
 double		ParamReader::rmax								=0;			//param:
 bool		ParamReader::LOAD_MODEL							=0;
 bool		ParamReader::SAVE_MODEL							=0;

 //planners
 int		ParamReader::GRD_EST_SAMPLE_SIZE				=5;			//param: number of samples we pick from our generalizers when we try to appx a transition
 int		ParamReader::GRD_DISCRETIZED_SIZE				=20 ; 		//param:how many cells per continuous dimension should we have
 double		ParamReader::PLN_VI_EPSILON						= 0.0001;	//param: when value iteration stops
 int		ParamReader::FVI_DISCRETIZED_SIZE				=10;		//how many samples per dimension
 int		ParamReader::FVI_BACKUP_SAMPLES					=3000;		//how many samples per dimension
 int		ParamReader::FVI_MC_LENGTH						=50;	//how deep monte carlo rollouts are

 double		ParamReader::FMLKR_SIGMA						=0.1; 		//the width of the gaussian kernel
 int		ParamReader::FMLKR_K							=20; 		//number of neighbors to consider
 bool		ParamReader::MAHALANOBIS_USE_PCA				= true;		//whether the second PCA dim reduction should be used 


 bool ParamReader::load(const char * fname)
 {
	 try{
	 cfgFile.open(fname);
	 }
	 catch(...)
	 {
		return false;
	 }
	 if (! cfgFile.is_open())
		 return false;

	//experiment
	readInt("EXP_NUM_RUNS",ParamReader::EXP_NUM_RUNS);
	readInt("EXP_NUM_EPISODES", ParamReader::EXP_NUM_EPISODES);
	readInt("EXP_NUM_STEPS",ParamReader::EXP_NUM_STEPS);
	readInt("EXP_TYPE", ParamReader::EXP_TYPE);



	//agent
	readInt("AGNT_USE_GENERALIZATION_TIME",ParamReader::AGNT_USE_GENERALIZATION_TIME);
	readInt("AGNT_USE_GENERALIZATION_END_TIME", ParamReader::AGNT_USE_GENERALIZATION_END_TIME);
	readBool("AGNT_USE_GENERALIZATION",ParamReader::AGNT_USE_GENERALIZATION);
	readInt("AGNT_SOLVE_PERIOD",ParamReader::AGNT_SOLVE_PERIOD);
	readInt("AGNT_LEARN_GENERALIZATION_END_TIME", ParamReader::AGNT_LEARN_GENERALIZATION_END_TIME);
	readInt("AGNT_BATCH_LEARNING_TIME", ParamReader::AGNT_BATCH_LEARNING_TIME);
	readInt("AGNT_RUN_TIMEOUT", ParamReader::AGNT_RUN_TIMEOUT);
	readInt("AGNT_BATCH_LEARNING_END_TIME", ParamReader::AGNT_BATCH_LEARNING_END_TIME);
	readInt("AGNT_LEARN_GENERALIZATION_END_TIME", ParamReader::AGNT_LEARN_GENERALIZATION_END_TIME);

	readDouble("GAMMA",ParamReader::GAMMA);
	readDouble("rmax",ParamReader::rmax);
	readBool("LOAD_MODEL", ParamReader::LOAD_MODEL);
	readBool("SAVE_MODEL", ParamReader::SAVE_MODEL);

	//planners
	readInt("GRD_EST_SAMPLE_SIZE",ParamReader::GRD_EST_SAMPLE_SIZE);
	readInt("GRD_DISCRETIZED_SIZE",ParamReader::GRD_DISCRETIZED_SIZE);
	readDouble("PLN_VI_EPSILON", ParamReader::PLN_VI_EPSILON);
	readInt("FVI_DISCRETIZED_SIZE", ParamReader::FVI_DISCRETIZED_SIZE);
	readInt("FVI_BACKUP_SAMPLES", ParamReader::FVI_BACKUP_SAMPLES);
	readInt("FVI_MC_LENGTH", ParamReader::FVI_MC_LENGTH);

	readDouble("FMLKR_SIGMA", ParamReader::FMLKR_SIGMA);
	readInt("FMLKR_K", ParamReader::FMLKR_K);
	readBool("MAHALANOBIS_USE_PCA", ParamReader::MAHALANOBIS_USE_PCA); 

	cfgFile.close();
	return true;
 }

void ParamReader::print()
{
printf("---------params---------------\n");
printf("Experiment parameters: \n");
	printf("\tEXP_NUM_RUNS\t\t%d \n",ParamReader::EXP_NUM_RUNS );
	printf("\tEXP_NUM_EPISODES\t%d \n", ParamReader::EXP_NUM_EPISODES);
	printf("\tEXP_NUM_STEPS\t\t%d \n",ParamReader::EXP_NUM_STEPS );
	printf("\tEXP_TYPE\t\t%d \n", ParamReader::EXP_TYPE);


printf("Agent params: \n");
	printf("\tUSE_GENERALIZATION_TIME\t\t%d \n",ParamReader::AGNT_USE_GENERALIZATION_TIME );
	printf("\tUSE_GENERALIZATION_END_TIME\t%d \n", ParamReader::AGNT_USE_GENERALIZATION_END_TIME);
	printf("\tUSE_GENERALIZATION\t\t%d \n",ParamReader::AGNT_USE_GENERALIZATION );
	printf("\tLEARN_GENERALIZATION\t\t%d \n", ParamReader::AGNT_LEARN_GENERALIZATION);
	printf("\tBATCH_LEARNING_END_TIME\t\t%d \n", ParamReader::AGNT_BATCH_LEARNING_END_TIME);
	printf("\tBATCH_LEARNING_TIME\t\t%d \n", ParamReader::AGNT_BATCH_LEARNING_TIME);
	printf("\tSOLVE_PERIOD\t\t%d \n",ParamReader::AGNT_SOLVE_PERIOD );
	printf("\tLEARN_GENERALIZATION_END_TIME\t%d \n", ParamReader::AGNT_LEARN_GENERALIZATION_END_TIME);

	printf("Planner params:\n");
	printf("\tPLN_VI_EPSILON\t\t\t%lf \n", PLN_VI_EPSILON);
	printf("\tGRD_EST_SAMPLE_SIZE\t\t%d \n",ParamReader::GRD_EST_SAMPLE_SIZE );
	printf("\tGRD_DISCRETIZED_SIZE\t\t%d \n",ParamReader::GRD_DISCRETIZED_SIZE );
	printf("\tFVI_DISCRETIZED_SIZE\t\t%d \n",ParamReader::FVI_DISCRETIZED_SIZE );
	printf("\tFVI_BACKUP_SAMPLES\t\t%d \n", FVI_BACKUP_SAMPLES);
	printf("\tFVI_MC_LENGTH\t\t\t%d \n", FVI_MC_LENGTH);

	printf("Learners:\n");
	printf("\tFMLKR_SIGMA\t\t\t\t%lf\n", ParamReader::FMLKR_SIGMA);
	printf("\tFMLKR_K\t\t\t\t%d\n", ParamReader::FMLKR_K);
	printf("\tMAHALANOBIS_USE_PCA\t\t\t%d\n", ParamReader::MAHALANOBIS_USE_PCA); 
	printf("Other params:\n");
	printf("\tGAMMA\t\t\t\t%lf \n",ParamReader::GAMMA );
	printf("\tLOAD_MODEL\t\t\t%d	\n", LOAD_MODEL);
	printf("\tSAVE_MODEL\t\t\t%d	\n", SAVE_MODEL);
	printf("\trmax\t\t\t\t%lf \n", ParamReader::rmax);

	printf("------------------------------\n");



 }


//! returns true if the (0-terminated) string s contains c
  inline bool contains(const char* s,char c){
    for(int i=0;s[i];i++) if(s[i]==c) return true;
    return false;
  }

  //! skips the chars (typically white characters) when parsing from the istream
  inline char skip(std::istream& is,char* skipchars){
    char c;
    do{ c=is.get(); } while(contains(skipchars,c));
    is.putback(c);
    return c;
  }



char ParamReader::getNextChar(std::ifstream& cfg)
{
	if (! cfg.good())
		return '\n';

	char c = cfg.get();
	if (c == '#')
	{
		while (cfg.good())
		{
			c = cfg.get();
			if (c == '\n')
				return c;
		}
		return '\n';
	}
	return c;
}


bool ParamReader::skip2param(const char* tag)
{
	cfgFile.clear();
	cfgFile.seekg(std::ios::beg);
	if(!cfgFile.good()) return false;

	unsigned n=strlen(tag);
	char *buf=new char [n+2]; memset(buf,0,n+2);
	while(cfgFile.good()){
		memmove(buf,buf+1,n);
		buf[n]=getNextChar(cfgFile);

		if (buf[n] =='#')
			skip(cfgFile,"\n");
		if(buf[n]==' ' || buf[n]=='\t' || buf[n]==':' || buf[n]=='=')
		{
			buf[n]=0;
			if(!strcmp(tag,buf))
				break;
			buf[n]=':';
		}
	};
	delete[] buf;

	if(!cfgFile.good()) return false;

	skip(cfgFile," :=\n\r\t");

	return true;
}

int ParamReader::readInt(const char* tag, int& value)
{

	if (skip2param(tag))
		cfgFile >>value;

	return value;
}


double ParamReader::readDouble(const char* tag, double& value)
{

	if (skip2param(tag))
		cfgFile >>value;

	return value;
}


char* ParamReader::readString(const char* tag, char*& value)
{

	if (skip2param(tag))
	cfgFile >>value;

	return value;
}

bool ParamReader::readBool(const char* tag, bool& value)
{

	if (skip2param(tag))
		cfgFile >>value;

	return value;
}

